home *** CD-ROM | disk | FTP | other *** search
/ PsL Monthly 1993 December / PSL Monthly Shareware CD-ROM (December 1993).iso / prgmming / dos / pascal / miscuni.com / MESSAGES.PAS < prev    next >
Encoding:
Pascal/Delphi Source File  |  1989-05-25  |  13.4 KB  |  368 lines

  1. {.he Popup Message Module - %F}
  2. (**************************************************************************)
  3. (*                              Messages                                  *)
  4. (*                                                                        *)
  5. (*  Author:  Geoffrey Moehrke                                             *)
  6. (*  Date:    May 25, 1989                                                 *)
  7. (*                                                                        *)
  8. (*  Purpose: Put variable line message window on screen. Messages are     *)
  9. (*           passed with embedded formatting codes to determine number of *)
  10. (*           lines, changes in screen attributes, justification, etc.     *)
  11. (*                                                                        *)
  12. (*  Source:  F:\TP\UNIT\MESSAGES.PAS                                      *)
  13. (**************************************************************************)
  14. Unit Messages;
  15.  
  16. Interface
  17.  
  18.   Uses TPCRT,
  19.  
  20.        {$IFDEF UseClock}
  21.        TPClock,
  22.        {$ENDIF}
  23.  
  24.        TPWindow,
  25.        TPString,
  26.        Stacks;
  27.  
  28.   Const CmdPre = #0;                    { Itentifies beginning of embedded }
  29.                                         { command sequence within a string }
  30.  
  31. { The following command sequences are valid within message strings         }
  32.  
  33.         NewLnCmd  = #0#1;               { Start following text on new line }
  34.         TitleCmd  = #0#6;               { Put a header on the message      }
  35.                                         { text (and valid commands) of     }
  36.                                         { header should be enclosed by     }
  37.                                         { TitleCmd                         }
  38.         DelayCmd  = #0#12;              { DelayCmd + #n - delay n seconds  }
  39.                                         { or until key pressed - actual    }
  40.                                         { time will depend somewhat on     }
  41.                                         { the processor, but will be close }
  42.                                         { to specified.                    }
  43.  
  44. {  The following command sequences are valid within message window titles  }
  45.  
  46.         BeepCmd  = #0#7;                { Beep when displaying             }
  47.         RowCmd   = #0#8;                { RowCmd + #n -  Set top row to n  }
  48.                                         { if possible.                     }
  49.         ColCmd   = #0#9;                { ColCmd + #n - Set first col to n }
  50.                                         { if possible                      }
  51.         PauseCmd = #0#10;               { Pause until key pressed          }
  52.         LeaveCmd = #0#11;               { Leave window up until RemoveMsg  }
  53.                                         { is called                        }
  54.         LeftCmd   = #0#3;               { Left justify message in window   }
  55.         RightCmd  = #0#4;               { Right justify message in window  }
  56.         CenterCmd = #0#5;               { Center message in window         }
  57.  
  58.  
  59.   type MsgStr = String;
  60.        JustifyType = (Left, Right, Cntr);
  61.        CStr = String[3];
  62.  
  63.    type
  64.        ReadKeyFunc = Function : Word;
  65.        LoopProc = Procedure;
  66.  
  67. { The following are the default variables for messages                     }
  68.  
  69.   Var   MsgWinTopRow,                   { Try to place top of window at    }
  70.                                         { this row - will move up if not   }
  71.                                         { room.  0 for centered window.    }
  72.  
  73.         MsgWinFirstCol: byte;           { Try to place left edge of window }
  74.                                         { at this column - will move left  }
  75.                                         { if not room.  0 for centered win.}
  76.  
  77.         MsgWinColor: FlexAttrs;         { Default message window colors    }
  78.         MsgFrameColor,
  79.         MsgTitleColor,
  80.         MsgWinDefLen : Byte;
  81.  
  82.         MsgJust : JustifyType;          { Default justification - usually  }
  83.                                         { Cntr.                            }
  84.  
  85.         MsgDisposeCh : boolean;         { When waiting for keypress in     }
  86.                                         { paused message window - dispose  }
  87.                                         { the key pressed.                 }
  88.  
  89.         MsgReadKW : ReadKeyFunc;        { User definable read key function  }
  90.         MsgLoopProc : LoopProc;         { User definable proc. to call while}
  91.                                         { waiting for key                   }
  92.  
  93. {  Message strings are written using TPCRT's FlexWriteWindow commands      }
  94. {  attributes for these message strings can be changed by inserting        }
  95. {  the appropriate control characters into the strings.                    }
  96.  
  97.   procedure SetMsgDefaults( WindowColor: FlexAttrs; FrameColor, TitleColor,
  98.                             TopRow, TopCol: byte; Just: JustifyType );
  99.     {-Change the default characteristics of message windows. }
  100.  
  101.   function CmdStr( Cmd: CStr; P:byte ): CStr;
  102.     {-Compose a command string consisting of the command and the
  103.       parameter byte converted to a char.}
  104.  
  105.   procedure Message( S : MsgStr );
  106.     {-Message driver - displays S in a box formatted as specified. }
  107.  
  108.   procedure RemoveMsg;
  109.     {-Remove message from screen if left on previously using LeaveCmd. }
  110.  
  111. {==========================================================================}
  112. Implementation
  113.  
  114.    var MsgWindow : WindowPtr;
  115.        MsgActive : Byte;
  116.        MsgStack  : Stack;
  117.  
  118. procedure SetMsgDefaults( WindowColor: FlexAttrs; FrameColor, TitleColor,
  119.                           TopRow, TopCol: byte; Just: JustifyType );
  120.     {-Change the default characteristics of message windows. }
  121.  
  122.   begin
  123.     MsgWinColor    := WindowColor;
  124.     MsgFrameColor  := FrameColor;
  125.     MsgTitleColor  := TitleColor;
  126.     MsgWinTopRow   := TopRow;
  127.     MsgWinFirstCol := TopCol;
  128.     Msgjust := Just;
  129.   end;
  130.  
  131. function CmdStr( Cmd: CStr; P:byte ): CStr;
  132.     {-Compose a command string consisting of the command and the
  133.       parameter byte converted to a char.}
  134.  
  135.   begin
  136.     CmdStr := Cmd + Char(P);
  137.   end;
  138.  
  139.   function MsgLength( S : String) : byte;
  140.     {-Return the display length of a string possibly containing containing
  141.       attribute commands                                                    }
  142.  
  143.     var I, Temp: byte;
  144.  
  145.   begin
  146.     Temp := 0;
  147.     for I := 1 to Length(S) do
  148.       if Not (S[I] In [^A, ^B, ^C]) then
  149.         inc(Temp);
  150.     MsgLength := Temp;
  151.   end;
  152.  
  153. {$F+}
  154.   procedure NilLoopProc;
  155.     { -Default loop procedure - does absolutely nothing }
  156.   begin
  157.   end;
  158. {$F-}
  159.  
  160.   procedure Message( S : MsgStr );
  161.     {-Message driver - displays S in a box formatted as specified. }
  162.  
  163.     var WinColor   : FlexAttrs;
  164.         FrameColor,
  165.         TitleColor,
  166.         TopRow,
  167.         FirstCol,
  168.         DelaySec,
  169.         CmdPos,
  170.         TitleStart,
  171.         TitleEnd,
  172.         NumLines,
  173.         WinLength,
  174.         OldLen,
  175.         I           : byte;
  176.         DelayCount  : integer;
  177.         Just        : JustifyType;
  178.         H           : string;
  179.         MsgLines    : array[1..10] of string[80];
  180.         LeaveWin,
  181.         Pause,
  182.         BeepOn      : boolean;
  183.  
  184.   begin
  185.     Inc(MsgActive);
  186.     LeaveWin := False;
  187.     Pause := False;
  188.     BeepOn := False;
  189.     DelaySec := 0;
  190.     WinColor := MsgWinColor;
  191.     FrameColor := MsgFrameColor;
  192.     TitleColor := MsgTitleColor;   { Set all parameters to default values }
  193.     TopRow := MsgWinTopRow;
  194.     FirstCol := MsgWinFirstCol;
  195.     Just := MsgJust;
  196.     H := '';
  197.     TitleStart := Pos(TitleCmd,S); { Find window title if exists             }
  198.     if TitleStart <> 0 then begin
  199.         Delete(S,TitleStart,Length(TitleCmd));
  200.         TitleEnd := Pos(TitleCmd,S);
  201.         if TitleEnd = 0 then TitleEnd := Length(S);
  202.         Delete(S,TitleEnd,Length(TitleCmd));
  203.         H := Copy(S,TitleStart,TitleEnd-TitleStart);
  204.         Delete(S,TitleStart,TitleEnd-TitleStart);
  205.     end;
  206.     CmdPos := Pos(RowCmd,H);            { Look for command to set top row    }
  207.     If CmdPos <> 0 then begin
  208.       TopRow := byte(H[CmdPos+Length(RowCmd)]); { Interpret command          }
  209.       Delete(H,CmdPos,Length(RowCmd)+1);        { Remove it from string      }
  210.     end;
  211.     CmdPos := Pos(ColCmd,H);          { Look for command to set 1st col      }
  212.     If CmdPos <> 0 then begin
  213.       FirstCol := byte(H[CmdPos+Length(ColCmd)]);{ Interpret command         }
  214.       Delete(H,CmdPos,Length(ColCmd)+1);        { Remove it from string      }
  215.     end;
  216.     CmdPos := Pos(DelayCmd,H);        { Look for command to set delay time   }
  217.     If CmdPos <> 0 then begin
  218.       DelaySec := byte(H[CmdPos+Length(DelayCmd)]);{ Interpret command        }
  219.       Delete(H,CmdPos,Length(DelayCmd)+1);      { Remove it from string      }
  220.     end;
  221.     CmdPos := Pos(LeaveCmd,H);         { Look for command to leave window    }
  222.     if CmdPos <> 0 then begin
  223.       LeaveWin := True;
  224.       Delete(H,CmdPos,Length(LeaveCmd));
  225.     end;
  226.     CmdPos := Pos(PauseCmd,H);         { Look for command to pause           }
  227.     if CmdPos <> 0 then begin
  228.       Pause := True;
  229.       Delete(H,CmdPos,Length(PauseCmd));
  230.     end;
  231.     CmdPos := Pos(BeepCmd,H);          { Look for command to beep            }
  232.     if CmdPos <> 0 then begin
  233.       BeepOn := True;
  234.       Delete(H,CmdPos,Length(BeepCmd));
  235.     end;
  236.     CmdPos := Pos(LeftCmd,H);
  237.     If CmdPos <> 0 then
  238.       begin
  239.         Just := Left;
  240.         Delete(H,CmdPos,Length(LeftCmd));
  241.       end;
  242.     CmdPos := Pos(RightCmd,H);
  243.     If CmdPos <> 0 then
  244.       begin
  245.         Just := Right;
  246.         Delete(H,CmdPos,Length(RightCmd));
  247.       end;
  248.     CmdPos := Pos(CenterCmd,H);
  249.     If CmdPos <> 0 then begin
  250.         Just := Cntr;
  251.         Delete(H,CmdPos,Length(CenterCmd));
  252.     end;
  253.  
  254.  
  255.     NumLines := 0;             { begin dividing message into lines           }
  256.     CmdPos := Pos(NewLnCmd,S);
  257.     If CmdPos = 0 then         { Single line message                         }
  258.       begin
  259.         MsgLines[1] := S;
  260.         NumLines := 1;
  261.         S := '';
  262.       end
  263.     else while CmdPos <> 0 do begin  { multiple line message                 }
  264.       inc(NumLines);
  265.       MsgLines[NumLines] := Trim(Copy(S,1,CmdPos-1));
  266.       Delete(S,1,CmdPos+1);
  267.       CmdPos := Pos(NewlnCmd,S);
  268.     end;
  269.     if S <> '' then begin
  270.       inc(NumLines);
  271.       MsgLines[NumLines] := TrimTrail(S);
  272.     end;
  273.     WinLength := MsgWinDefLen;        { Get max len for window sizing   }
  274.     for I := 1 to NumLines do
  275.       if MsgLength(MsgLines[I]) > WinLength then
  276.         WinLength := MsgLength(MsgLines[I]);
  277.     if MsgLength(H) > WinLength then
  278.       WinLength := MsgLength(H);
  279.     if WinLength > ScreenWidth then
  280.       WinLength := ScreenWidth;{ dont let window exceed screen   }
  281.     if FirstCol = 0 then
  282.       FirstCol := 40 - (WinLength div 2)   { if not specified, center window }
  283.     else while WinLength + FirstCol >= 80 do { else make sure it fits        }
  284.       dec(FirstCol);
  285.     If TopRow = 0 then
  286.       TopRow := (ScreenHeight div 2) - (2+NumLines div 2);
  287.     while TopRow+NumLines+1 > ScreenHeight do
  288.       dec(TopRow);
  289.     if not MakeWindow( MsgWindow, FirstCol, TopRow, FirstCol + WinLength+1,
  290.                        TopRow+NumLines+1, True, True, False,
  291.                        WinColor[0], FrameColor, TitleColor,H) then ;
  292.     if DisplayWindow( MsgWindow ) then
  293.       for I := 1 to NumLines do begin
  294.         Case Just of
  295.           Left  : MsgLines[I] := Pad( MsgLines[I],WinLength );
  296.           Right : MsgLines[I] := LeftPad( MsgLines[I],WinLength );
  297.           Cntr  : begin
  298.                     MsgLines[I] := Center( MsgLines[I],WinLength);
  299.                     Insert(CharStr(' ',(Length(MsgLines[I])-
  300.                                    MsgLength(MsgLines[I])) Div 2), MsgLines[I],1);
  301.                   end
  302.         end;
  303.         FlexWriteWindow(MsgLines[I],I,1,WinColor);
  304.       end;
  305.     GotoXY(MsgLength(TrimTrail(MsgLines[I]))+1,I );
  306.     HiddenCursor;
  307.     if BeepOn Then begin
  308.       Sound(880); Delay(250); Nosound;
  309.     end;
  310.     DelayCount := 0;
  311.     If DelaySec > 0 then
  312.       repeat
  313.         Delay(10);
  314.         inc(DelayCount,10);
  315.       until KeyPressed Or (DelayCount >= 1000 * DelaySec);
  316.     if Pause then
  317.       repeat
  318.         MsgLoopProc;
  319.       until keypressed;
  320.     if MsgDisposeCh And Pause then
  321.       I := byte( MsgReadKW );
  322.     if not LeaveWin then
  323.       begin
  324.         MsgWindow := EraseTopWindow;
  325.         DisposeWindow(MsgWindow);
  326.         Dec(MsgActive)
  327.       end
  328.     else
  329.       if Not Push( MsgStack, @MsgWindow ) then begin { If no room on stack }
  330.         MsgWindow := EraseTopWindow;
  331.         DisposeWindow(MsgWindow);
  332.         Dec(MsgActive)
  333.       end
  334.   end;  { Msg }
  335.  
  336.  
  337.   procedure RemoveMsg;
  338.     {-Remove message from screen if left on previously usin LeaveCmd. }
  339.  
  340.     begin
  341.       MsgWindow := WindowPtr(Pop(MsgStack)^);
  342.       if SetTopWindow(MsgWindow) then
  343.         begin
  344.           MsgWindow := EraseTopWindow;
  345.           DisposeWindow(MsgWindow);
  346.           Dec(MsgActive);
  347.         end;
  348.     end;
  349.  
  350.  
  351.   const
  352.     DefMonoAtts : FlexAttrs = ($70, $07, $0F, $FF);
  353.     DefColorAtts: FlexAttrs = ($4F, $4E, $4C, $40);
  354.  
  355. begin
  356.   InitStack(MsgStack, SizeOf(WindowPtr) );
  357.   MsgReadKW := ReadKeyWord;
  358.   MsgLoopProc := NilLoopProc;
  359.   MsgActive := 0;
  360.   MsgDisposeCh := True;
  361.   MsgWinDefLen := 0;
  362.   if LastMode In [0, 2, 7] then
  363.     SetMsgDefaults(DefMonoAtts, $70, $70, 0, 0,Cntr)
  364.   Else
  365.     SetMsgDefaults(DefColorAtts, $47, $47, 0, 0, Cntr);
  366. end.  { Unit Messages }
  367.  
  368.